/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.academik.controller;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Iterator;
import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.context.FacesContext;
import javax.faces.model.SelectItem;
import org.academik.model.Grado;
import org.academik.model.Nivel;
import org.academik.util.FacesUtil;
import org.academik.util.HibernateUtil;
import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.criterion.Order;

/**
 *
 * @author Javier
 */
@ManagedBean(name = "gradoBean")
@ViewScoped
public class GradoBean extends AbstractViewScopedBean implements Serializable {

    /** Declaracion de variables */
    private Grado grado;
    private ArrayList grados;
    private Long selectedNivel;
    private Grado selectedGrado;
    private boolean cargarGrado;

    /** Creates a new instance of GradoBean */
    public GradoBean() {
        this.nuevo();
    }

    @Override
    public void crear() {
        //System.out.print(this.selectedNivel);
        Session session = HibernateUtil.getSessionFactory().openSession();
        Transaction tx = null;
        try {
            tx = (Transaction) session.beginTransaction();
            Nivel tempNivel = (Nivel) session.load(Nivel.class, this.selectedNivel);
            this.grado.setNivel(tempNivel);

            if (this.cargarGrado == false) {
                this.grado.setNuGrado(this.generarCorrelativo(session));
            }

            session.saveOrUpdate(this.grado);
            session.flush();
            session.clear();
            tx.commit();
            this.nuevo();
            FacesContext.getCurrentInstance().addMessage(null,
                    new FacesMessage(FacesMessage.SEVERITY_INFO, "Información:", "El grado se creo satisfactoriamente"));
        } catch (HibernateException e) {
            tx.rollback();
            FacesUtil.hibernateException(e);
        } finally {
            session.close();
        }
    }

    @Override
    public void eliminar() {
        Session session = HibernateUtil.getSessionFactory().openSession();
        Transaction tx = null;
        Grado s = (Grado) session.load(Grado.class, this.selectedGrado.getIdGrado());
        int numeroGrado = this.selectedGrado.getNuGrado();
        try {
            tx = (Transaction) session.beginTransaction();
            session.delete(s);
            session.flush();
            session.clear();
            tx.commit();
            this.reordenar(numeroGrado);
            this.nuevo();
            FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, "Información:", "Registro eliminado satisfactoriamente"));
        } catch (HibernateException e) {
            tx.rollback();
            FacesUtil.hibernateException(e);
        } finally {
            session.close();
        }
    }

    @Override
    public void cargarOpciones() {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public void cargarOpciones(int id) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public void buscar() {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public void modificar() {
        this.cargarGrado = true;
        this.grado = new Grado();
        this.selectedNivel = this.selectedGrado.getNivel().getIdNivel();
        this.grado = this.selectedGrado;
    }

    @Override
    public void cargarResgistros() {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    @Override
    public void nuevo() {
        this.grado = new Grado();
        this.grados = new ArrayList();
        this.selectedNivel = null;
        this.selectedGrado = null;
        this.cargarGrado = false;
        this.populateGrados();
    }

    /** Reordenar los registros cuando se elimine uno*/
    public void reordenar(int gradoEliminado) {
        Session session = HibernateUtil.getSessionFactory().openSession();
        Transaction tx = null;
        String sql = "";
        try {
            tx = (Transaction) session.beginTransaction();
            sql = "UPDATE grado g "
                    + "SET g.nuGrado = g.nuGrado - 1 "
                    + "WHERE g.nuGrado > :numero";
            session.createSQLQuery(sql).setParameter("numero", gradoEliminado).executeUpdate();
            session.flush();
            session.clear();
            tx.commit();
            FacesContext.getCurrentInstance().addMessage(null,
                    new FacesMessage(FacesMessage.SEVERITY_INFO,
                    "Informacion:", "Los grados fueron reordenados"));
        } catch (HibernateException e) {
            tx.rollback();
            FacesUtil.hibernateException(e);
        } finally {
            session.close();
        }
    }

    /** Genera el numero del nivel*/
    public int generarCorrelativo(Session session) {
        int numero = 1;
        String sql = "SELECT MAX(g.nuGrado) FROM grado g";
        Query query = session.createSQLQuery(sql);
        if (query.uniqueResult() != null) {
            numero = ((Integer) query.uniqueResult()).intValue() + 1;
        }
        return numero;
    }

    /** Muestra los datos de la BD en la tabla*/
    public void populateGrados() {
        Session session = HibernateUtil.getSessionFactory().openSession();
        String sql = "SELECT g, n "
                + "FROM Grado g JOIN g.nivel n " /*Hala el grado y el nivel alque esta amarrado*/
                + "ORDER BY g.nuGrado ASC";
        Query query = session.createQuery(sql);
        this.grados = (ArrayList) query.list();
        session.close();
    }

    /** Subir el grado (pasar de posicion 2 a 3 por ejemplo)*/
    public void subir() {
        Session session = HibernateUtil.getSessionFactory().openSession();
        Grado tempGrado = this.selectedGrado;
        int numeroGrado = this.selectedGrado.getNuGrado();
        int max = numeroGrado;
        String sql = "SELECT MAX(g.nuGrado) FROM grado g";
        Query query = session.createSQLQuery(sql);
        if (query.uniqueResult() != null) {
            max = ((Integer) query.uniqueResult()).intValue();
        }
        if (numeroGrado < max) {
            Transaction tx = null;
            try {
                tx = (Transaction) session.beginTransaction();
                tempGrado.setNuGrado(numeroGrado + 1);
                session.saveOrUpdate(tempGrado);
                sql = "UPDATE grado g "
                        + "SET g.nuGrado = g.nuGrado - 1 "
                        + "WHERE g.nuGrado = :numero";
                session.createSQLQuery(sql).setParameter("numero", numeroGrado + 1).executeUpdate();
                session.flush();
                session.clear();
                tx.commit();
                this.nuevo();
                FacesContext.getCurrentInstance().addMessage(null,
                        new FacesMessage(FacesMessage.SEVERITY_INFO,
                        "Informacion:", "El grado '" + tempGrado.getVcNomGrado() + "' se movio a la posicion " + (numeroGrado + 1)));
            } catch (HibernateException e) {
                tx.rollback();
                FacesUtil.hibernateException(e);
            } finally {
                this.nuevo();
            }
        }
        session.close();
    }

    /** Bajar el grado (pasar de posicion 3 a 2 por ejemplo)*/
    public void bajar() {
        Session session = HibernateUtil.getSessionFactory().openSession();
        Grado tempGrado = this.selectedGrado;
        int numeroGrado = this.selectedGrado.getNuGrado();
        int min = numeroGrado;
        String sql = "SELECT MIN(g.nuGrado) FROM grado g";
        Query query = session.createSQLQuery(sql);
        if (query.uniqueResult() != null) {
            min = ((Integer) query.uniqueResult()).intValue();
        }
        if (numeroGrado > min) {
            Transaction tx = null;
            try {
                tx = (Transaction) session.beginTransaction();
                tempGrado.setNuGrado(numeroGrado - 1);
                session.saveOrUpdate(tempGrado);
                sql = "UPDATE grado g "
                        + "SET g.nuGrado = g.nuGrado + 1 "
                        + "WHERE g.nuGrado = :numero";
                session.createSQLQuery(sql).setParameter("numero", numeroGrado - 1).executeUpdate();
                session.flush();
                session.clear();
                tx.commit();
                this.nuevo();
                FacesContext.getCurrentInstance().addMessage(null,
                        new FacesMessage(FacesMessage.SEVERITY_INFO,
                        "Informacion:", "La grado '" + tempGrado.getVcNomGrado() + "' se movio a la posicion " + (numeroGrado - 1)));
            } catch (HibernateException e) {
                tx.rollback();
                FacesUtil.hibernateException(e);
            } finally {
                this.nuevo();
            }
        }
        session.close();
    }

    /**
     * Carga la lista que sera mostrada en un cuadro de lista desplegable
     */
    public ArrayList<SelectItem> cargarGrados() {
        ArrayList<SelectItem> lista = new ArrayList<SelectItem>();
        Session session = HibernateUtil.getSessionFactory().openSession();
        Criteria cSeccion = session.createCriteria(Grado.class);
        cSeccion.addOrder(Order.asc("nuGrado"));
        Iterator iter = cSeccion.list().iterator();

        while (iter.hasNext()) {
            Grado s = (Grado) iter.next();
            lista.add(new SelectItem(s.getIdGrado(), s.getVcNomGrado(), ""));
        }
        session.close();
        return lista;
    }

    /**
     * Carga la lista que sera mostrada en un cuadro de lista desplegable con parametro
     */
    public ArrayList<SelectItem> cargarListaGrados(Long idNivel) {
        ArrayList<SelectItem> lista = new ArrayList<SelectItem>();
        Session session = HibernateUtil.getSessionFactory().openSession();
        if (idNivel != null) {
            Nivel levels = (Nivel) session.load(Nivel.class, idNivel);
            Iterator iter = levels.getGrados().iterator();

            while (iter.hasNext()) {
                Grado s = (Grado) iter.next();
                lista.add(new SelectItem(s.getIdGrado(), s.getVcNomGrado(), ""));
            }
        }
        session.close();
        return lista;
    }

    /** Getters & Setters */
    public Grado getGrado() {
        return grado;
    }

    public void setGrado(Grado grado) {
        this.grado = grado;
    }

    public ArrayList<Grado> getGrados() {
        return grados;
    }

    public void setGrados(ArrayList<Grado> grados) {
        this.grados = grados;
    }

    public Long getSelectedNivel() {
        return selectedNivel;
    }

    public void setSelectedNivel(Long selectedNivel) {
        this.selectedNivel = selectedNivel;
    }

    public Grado getSelectedGrado() {
        return selectedGrado;
    }

    public void setSelectedGrado(Grado selectedGrado) {
        this.selectedGrado = selectedGrado;
    }
}
